using System;
using System.Collections.Generic;
using System.Text;
using System.Drawing;
using System.Windows.Forms;
using System.Media;
using System.IO;


using System.Runtime.Remoting;

using System.Runtime.Remoting.Channels;
using System.Runtime.Remoting.Channels.Tcp;
using System.Collections;
using System.Runtime.Serialization.Formatters;
using MULENetworking;

namespace MainGame
{
  
    class Engine
    {
        //Various game states.
        public enum engineStates
        {
            TitleScreen = 0, ChoosePlot = 1, Waiting = 2, PlayerTurn = 3,
            Auction = 4, Standings = 5, GameOver = 6, House = 7
        }

        public enum auctionStates
        {
            PreAuction = 0, Food = 1, Energy = 2, Smithore = 3, Crystite = 4
        }

        private ClientPlayer[] players; //player array from server
        private int pnum; //current client player
        protected IRemoteServer server;
        private SizeF GameArea;
        protected engineStates currentState;
        protected auctionStates auctionState;
        private ClientMap map; //map from server
        private static Random random = new Random();
        private static Font strfont = new Font("Arial", 24);
        private static Brush strbrush = new SolidBrush(Color.White);
        private static Font strfont2 = new Font("Arial", 14);
        private static Brush strbrush2 = new SolidBrush(Color.DarkOrange);
        private static Brush strbrush3 = new SolidBrush(Color.Black);
        protected Bitmap mulepicked ; // Symbol for type of mule piked
        protected Rectangle bsfood,bsenergy,bssmithore,bscrystite;
        private Boolean chooseEnabled = true;
        private Boolean hasMule = false; //Determines if player has mule (true after Buy Mule)
        private int muleselected = 0; // Determines what type of mule it wants
        protected int bid;//this is your bid chosen in auction graph

        
        private string netServer;

        
        public Engine(SizeF gamearea, string serverInfo, int player)
        {
            GameArea = gamearea;
            pnum = player - 1;   
            netServer = serverInfo;
            StartTCP();
            InitializeRemotingWithServer();
        }

        private void InitializeRemotingWithServer()
        {
            server =
               (IRemoteServer)Activator.GetObject(typeof(IRemoteServer), netServer);
            //RemotingConfiguration.RegisterWellKnownClientType(typeof(IRemoteServer), connectAddress);
            //if this fails we should focus on tcpServerAddress
            
        }

        private void StartTCP()
        {
            BinaryClientFormatterSinkProvider clientProvider = new BinaryClientFormatterSinkProvider();
            BinaryServerFormatterSinkProvider serverProvider = new BinaryServerFormatterSinkProvider();
            serverProvider.TypeFilterLevel = System.Runtime.Serialization.Formatters.TypeFilterLevel.Full;

            IDictionary props = new Hashtable();
            props["port"] = 0;
            string s = System.Guid.NewGuid().ToString();
            props["name"] = s;
            props["typeFilterLevel"] = TypeFilterLevel.Full;
            TcpChannel tcpChan = new TcpChannel(
                props, clientProvider, serverProvider);

            ChannelServices.RegisterChannel(tcpChan, false);
        }
       
        
        public void Initialize()
        {
            players = new ClientPlayer[4];
            currentState = engineStates.TitleScreen;
            auctionState = auctionStates.PreAuction;
            Sounds.Start();

            #region Test
            //TEST CODE FOR ME
            /*
            map = new Map(); //This should really come from the network
            players = new IPlayer[1];
            players[pnum] = new Player("Pedro", 2);
            players[pnum].avatar = 1;
            players[pnum].color = Color.Red;
             * */
            #endregion
        }

        public void UpdateClient()
        {
            players[0] = (ClientPlayer)server.CurrentGame.Player1;
            players[1] = (ClientPlayer)server.CurrentGame.Player2;
            players[2] = (ClientPlayer)server.CurrentGame.Player3;
            players[3] = (ClientPlayer)server.CurrentGame.Player4;
            map = (ClientMap)server.CurrentGame.GameMap;
        }

        public void SendPlayer()
        {
            players[pnum].PlayerState = (int)currentState;
            switch (pnum)
            {
                case 0:
                    server.CurrentGame.Player1 = players[pnum];
                    break;
                case 1:
                    server.CurrentGame.Player2 = players[pnum];
                    break;
                case 2:
                    server.CurrentGame.Player3 = players[pnum];
                    break;
                case 3:
                    server.CurrentGame.Player4 = players[pnum];
                    break;
                default:
                    break;
            }
        }

      //  public void SendMap()
        //{
          //  server.CurrentGame.GameMap = map;
        //}
            
       
        //Drawing Methods for different states
        #region Drawing Methods
     
        public void Draw(Graphics g)
        {
            //this.UpdateClient();
            switch ((int)currentState)
            {
                case 0:
                    drawTitle(g);
                    break;
                case 1:
                case 2:
                case 3:
                    drawMain(g);
                    break;
                case 4:
                    drawAuction(g);
                    break;
                case 5:
                case 6:
                    drawStandings(g);
                    break;
                case 7:
                    drawHouse(g);
                    break;
                default:
                    break;
            }
        }
    
        public void drawTitle(Graphics g)
        {
            Bitmap title = new Bitmap("titlescreen.bmp");
            g.DrawImage(title,0,0,900,500);
        }
    
        public void drawAuction(Graphics g)
        {
            int x;
            int y;

            #region PREAUCTION
		if (auctionState == auctionStates.PreAuction)
            {
                ///NEED VARIABLE TO SAVE STATUS AS SELLING OR NOT
                Bitmap pre = new Bitmap("preauctionscreen.bmp");
                g.DrawImage(pre, 0, 0, 900, 500);
                if (bsfood != null)
                {
                    g.FillRectangle(strbrush2, bsfood);
                }
                if (bsenergy != null)
                {
                    g.FillRectangle(strbrush2, bsenergy);
                }
                if (bscrystite != null)
                {
                    g.FillRectangle(strbrush2, bscrystite);
                }
                if (bssmithore != null)
                {
                    g.FillRectangle(strbrush2, bssmithore);
                }

                ///DRAWS STAT FOR EACH PLAYER
                int i = 0;
                this.UpdateClient();
                foreach (ClientPlayer p in players)
                {
                    
                    y = 160 + (60*i);
                    x = 390;
                    g.DrawString(p.food.ToString(), strfont2, strbrush3, x, y);
                    g.DrawString(p.smithore.ToString(), strfont2, strbrush3, x + 70, y);
                    g.DrawString(p.energy.ToString(), strfont2, strbrush3, x + 140, y);
                    g.DrawString(p.crystite.ToString(), strfont2, strbrush3, x + 210, y);
                    g.DrawString(p.money.ToString(), strfont2, Brushes.DarkOrange, x + 280, y);
                    p.DrawIcon(g, new Point(200, y-18), new Size(30, 35));
                    i++;
                }

            }

	#endregion

            #region AUCTIONS
            else
            {
                Bitmap pre = new Bitmap("auctionscreen.bmp");
                g.DrawImage(pre, 0, 0, 900, 500);

                //if (bid != null)
                  //  g.DrawLine(Pens.Red, 211, bid, 211 + 495, bid);

                this.UpdateClient();
                //Draws Bid Line foreach player
                foreach (IPlayer p in players)
                    g.DrawLine(new Pen(p.color), 211, p.Bid, 211 + 495, p.Bid);

                x = 226;

                if (auctionState == auctionStates.Food)
                {
                    g.DrawString("FOOD", strfont, strbrush, 100, 25);
                    g.DrawString("FOOD", strfont, strbrush, 690, 25);

                    this.UpdateClient();
                    //Prints Units and Money for each player
                    foreach (IPlayer p in players)
                    {
                        if (p.BidType == "sell")
                        {
                            y = 77;
                            g.DrawString(p.money.ToString(), strfont2, strbrush3, x, y);
                            g.DrawString(p.food.ToString(), strfont2, strbrush3, x, y + 30);
                        }
                        if (p.BidType == "buy")
                        {
                            y = 443;
                            g.DrawString(p.money.ToString(), strfont2, strbrush3, x, y + 30);
                            g.DrawString(p.food.ToString(), strfont2, strbrush3, x, y);
                        }
                        x += 70;
                    }
                }
                else if (auctionState == auctionStates.Energy)
                {
                    g.DrawString("ENERGY", strfont, strbrush, 100, 25);
                    g.DrawString("ENERGY", strfont, strbrush, 690, 25);

                    this.UpdateClient();
                    //Prints Units and Money for each player
                    foreach (IPlayer p in players)
                    {
                        if (p.BidType == "sell")
                        {
                            y = 77;
                            g.DrawString(p.money.ToString(), strfont2, strbrush3, x, y);
                            g.DrawString(p.energy.ToString(), strfont2, strbrush3, x, y + 30);
                        }
                        if (p.BidType == "buy")
                        {
                            y = 443;
                            g.DrawString(p.money.ToString(), strfont2, strbrush3, x, y + 30);
                            g.DrawString(p.energy.ToString(), strfont2, strbrush3, x, y);
                        }
                        x += 70;
                    }
                }
                else if (auctionState == auctionStates.Smithore)
                {
                    g.DrawString("SMITHORE", strfont, strbrush, 100, 25);
                    g.DrawString("SMITHORE", strfont, strbrush, 690, 25);

                    this.UpdateClient();
                    //Prints Units and Money for each player
                    foreach (IPlayer p in players)
                    {
                        if (p.BidType == "sell")
                        {
                            y = 77;
                            g.DrawString(p.money.ToString(), strfont2, strbrush3, x, y);
                            g.DrawString(p.smithore.ToString(), strfont2, strbrush3, x, y + 30);
                        }
                        if (p.BidType == "buy")
                        {
                            y = 443;
                            g.DrawString(p.money.ToString(), strfont2, strbrush3, x, y + 30);
                            g.DrawString(p.smithore.ToString(), strfont2, strbrush3, x, y);
                        }
                        x += 70;
                    }
                }
                else if (auctionState == auctionStates.Crystite)
                {
                    g.DrawString("CRYSTITE", strfont, strbrush, 100, 25);
                    g.DrawString("CRYSTITE", strfont, strbrush, 690, 25);

                    this.UpdateClient();
                    //Prints Units and Money for each player
                    foreach (IPlayer p in players)
                    {
                        if (p.BidType == "sell")
                        {
                            y = 77;
                            g.DrawString(p.money.ToString(), strfont2, strbrush3, x, y);
                            g.DrawString(p.crystite.ToString(), strfont2, strbrush3, x, y + 30);
                        }
                        if (p.BidType == "buy")
                        {
                            y = 443;
                            g.DrawString(p.money.ToString(), strfont2, strbrush3, x, y + 30);
                            g.DrawString(p.crystite.ToString(), strfont2, strbrush3, x, y);
                        }
                        x += 70;
                    }
                }
            } 
            #endregion

        }
      
        public void drawMain(Graphics g)
        {
            //g.Clear(Color.Empty);
            this.UpdateClient();
            map.Draw(g);

            if (currentState == engineStates.ChoosePlot)
            {
                g.DrawString("Please choose plot you wish to acquire...", strfont, strbrush, 150, 0);
            }
            if (currentState == engineStates.Waiting)
            {
                g.DrawString("Waiting for others to choose Plot", strfont, strbrush, 150, 0);
            }
            else if (currentState == engineStates.PlayerTurn)
            {
                foreach (ClientPlayer i in players)
                {
                    i.Draw(g);
                }
                RectangleF house = new Rectangle(400, 200, 100, 100);
                if (house.Contains(players[pnum].location))
                    currentState = engineStates.House;
                this.SendPlayer();
            }
        }

        public void drawHouse(Graphics g)
        {
            g.Clear(Color.White);

            Bitmap title = new Bitmap("townscreen.bmp");
            g.DrawImage(title, 0, 0, 900, 500);

            g.FillRectangle(Brushes.Blue,new Rectangle(310,125 + (37*muleselected),250,37));

            g.DrawString("ENERGY", strfont2, strbrush2, 345, 130);
            g.DrawString("MINING", strfont2, strbrush2, 345, 170);
            g.DrawString("FOOD", strfont2, strbrush2, 345, 210);
            g.DrawString("CRYSTITE", strfont2, strbrush2, 345, 250);

            if (hasMule)
            {
                g.DrawImage(new Bitmap("mulewhite.bmp"), 29, 170, 190, 190);
                g.DrawImage(new Bitmap("equipbutton.bmp"), 342, 308, 175, 70);
                g.DrawImage(new Bitmap("assaybutton.bmp"), 690, 308, 175, 70);
            }

            if (mulepicked != null)
                g.DrawImage(mulepicked,170,130,85,85);

        }

        public void drawStandings(Graphics g)
        {
            int x, y;
            Bitmap title = new Bitmap("standingscreen.bmp");
            g.DrawImage(title, 0, 0, 900, 500);

            ///DRAW ALL PLAYER STATS
            int i = 0;
            foreach (ClientPlayer p in players)
                { 
                    y = 155 + (56*i);
                    x = 333;
                    g.DrawString(p.money.ToString(), strfont2, strbrush3, x, y);
                    g.DrawString(p.landworth.ToString(), strfont2, strbrush3, x + 110, y);
                    g.DrawString(p.goodsworth.ToString(), strfont2, strbrush3, x + 200, y);
                    g.DrawString(p.networth.ToString(), strfont2, strbrush3, x + 330, y);
                    p.DrawIcon(g, new Point(195, y - 15), new Size(30, 35));
                    i++;
                }
        }

#endregion

        //EventHandlers for different states
        #region Mouse Events

        public void MouseDoubleClick(Point mlocation)
        {
            if (players[pnum].hasMule && currentState == engineStates.PlayerTurn)
            {
                int x, y;
                x = mlocation.X / 100;
                y = mlocation.Y / 100;
                server.CurrentGame.GameMap.Squares[x, y].Mule = players[pnum].muleType;
            }
        }

        public void MouseClick(Point mlocation)
        {
            switch ((int)currentState)
            {
                case 0:
                    mouseTitle(mlocation);
                    break;
                case 1:
                    mousePlot(mlocation);
                    break;
                case 2:
                    break;
                case 3:
                    mouseTurn(mlocation);
                    break;
                case 4:
                    mouseAuction(mlocation);
                    break;
                case 5:
                case 6:
                    mouseStandings(mlocation);
                    break;
                case 7:
                    mouseHouse(mlocation);
                    break;
                default:
                    break;
            }
        }
      

        public void mouseTitle(Point mlocation)
        {
            if (mlocation.X > 400 && mlocation.X < 540)
            {
                if (mlocation.Y > 275 && mlocation.Y < 400)
                {
                    currentState = engineStates.ChoosePlot;
                    Sounds.Stop();
                }
            }

        }
        

        public void mousePlot(Point mlocation)
        {
            int x,y;
            if (chooseEnabled)
            {
                x = mlocation.X / 100;
                y = mlocation.Y / 100;
                server.CurrentGame.GameMap.Squares[x, y].Owner = players[pnum];
                players[pnum].location = (PointF)mlocation;
                players[pnum].destination = (PointF)mlocation;
                this.SendPlayer();
                chooseEnabled = false;

                
                currentState = engineStates.Waiting;
                

            }
            else
                currentState = engineStates.Waiting;
        }
      

        public void mouseTurn(Point mlocation)
        {
            players[pnum].destination = (PointF)mlocation;
            this.SendPlayer();
        }
       

        public void mouseAuction(Point mlocation)
        {

            #region PREAUCTION
            if (auctionState == auctionStates.PreAuction)
            {
                Rectangle buy = new Rectangle(365, 367, 289, 26);
                Rectangle sell = new Rectangle(365, 396, 289, 26);

                int y;

                if (buy.Contains(mlocation))
                {
                    y = 367;
                    if (mlocation.X > 586)
                        bscrystite = new Rectangle(586, y, 69, 26);
                    else if (mlocation.X > 513)
                        bsenergy = new Rectangle(513, y, 69, 26);
                    else if (mlocation.X > 439)
                        bssmithore = new Rectangle(439, y, 69, 26);
                    else
                        bsfood = new Rectangle(366, y, 69, 26);


                }

                else if (sell.Contains(mlocation))
                {
                    y = 396;
                    if (mlocation.X > 586)
                        bscrystite = new Rectangle(586, y, 69, 26);
                    else if (mlocation.X > 513)
                        bsenergy = new Rectangle(513, y, 69, 26);
                    else if (mlocation.X > 439)
                        bssmithore = new Rectangle(439, y, 69, 26);
                    else
                        bsfood = new Rectangle(366, y, 69, 26);

                }

            } 
            #endregion

            else
            {
                Rectangle graph = new Rectangle(211,148,495,271);
                if (graph.Contains(mlocation))
                {
                    bid = mlocation.Y; //FIX THIS TO IMPLEMENT THE REAL BID FROM SERVER
                }
            }

        }
       

        public void mouseStandings(Point mlocation)
        {

        }
        

        public void mouseHouse(Point mlocation)
        {
            Rectangle list = new Rectangle(310, 125, 250, 150);
            Rectangle exit = new Rectangle(690,130,170,66);
            Rectangle buy = new Rectangle(348,314,175,70);
            Rectangle pub = new Rectangle(693,248,170,66);
            if (list.Contains(mlocation))
            {
                muleselected = (mlocation.Y - 125) / 37;
            }
            if (exit.Contains(mlocation))
            {
                players[pnum].destination = new PointF(420, 170);
                players[pnum].location = new PointF(420, 170);
                currentState = engineStates.PlayerTurn;
                this.SendPlayer();
            }

            if (buy.Contains(mlocation))
            {
                if (hasMule)
                {
                    //TODO: ADD MULE TO PLAYER
                    switch (muleselected)
                    {
                        case 0:
                            mulepicked = new Bitmap("menergy.bmp");
                            players[pnum].muleType="energy";
                            break;
                        case 1:
                            mulepicked = new Bitmap("mmining.bmp");
                            players[pnum].muleType = "mining";
                            break;
                        case 2:
                            mulepicked = new Bitmap("mfood.bmp");
                            players[pnum].muleType = "food";
                            break;
                        case 3:
                            mulepicked = new Bitmap("mcrystite.bmp");
                            players[pnum].muleType = "crystite";
                            break;
                    }
                 
                }
                else
                {
                    hasMule = true;
                    players[pnum].hasMule = true;
                    
                }
                this.SendPlayer();
            }
            if (pub.Contains(mlocation))
            {
                currentState=engineStates.Waiting;
                this.SendPlayer();
            }
        }
#endregion

    }
}
